package br.com.localfloripa.controllers;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;

import org.primefaces.event.RateEvent;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;

import br.com.localfloripa.dao.AnuncioDao;
import br.com.localfloripa.dao.AuditoriaDao;
import br.com.localfloripa.dao.EstadoDao;
import br.com.localfloripa.dao.MunicipioDao;
import br.com.localfloripa.dao.RamoDao;
import br.com.localfloripa.dao.ServicoDao;
import br.com.localfloripa.entities.Anuncio;
import br.com.localfloripa.entities.Auditoria;
import br.com.localfloripa.entities.Avaliacao;
import br.com.localfloripa.entities.Estado;
import br.com.localfloripa.entities.Mensagem;
import br.com.localfloripa.entities.Municipio;
import br.com.localfloripa.entities.Ramo;
import br.com.localfloripa.entities.Servico;
import br.com.localfloripa.entities.TipoAuditoria;
import br.com.localfloripa.entities.TipoAvaliacao;

@Named("searchController")
@Scope("session")
public class SearchController implements Serializable {
	
	private static final Logger log = LoggerFactory.getLogger(SearchController.class);
	private static final long serialVersionUID = 4581817886452126182L;
	private static final String UF_DEFAULT = "SC";
	private final Integer pageSize = 10;
		
	@Inject
	@Named("ramoDao")
	private RamoDao ramoDao;
	@Inject
	@Named("municipioDao")
	private MunicipioDao municipioDao;
	@Inject
	@Named("estadoDao")
	private EstadoDao estadoDao;	
	@Inject
	@Named("anuncioDao")
	private AnuncioDao anuncioDao;
	
	@Inject
	@Named("servicoDao")
	private ServicoDao servicoDao;
	
	@Inject
	@Named("auditoriaDao")
	private AuditoriaDao auditoriaDao;
	
	private LazyDataModel<Anuncio> lazyModelAnuncio; 
	
	/** form - atributos **/
	private Estado estado;
	private Municipio municipio;
	private Ramo ramo;
	private Avaliacao avaliacao;
	private Servico servico;
	private String searchField;
	private Mensagem mensagem;
	private String bairro;
	private Anuncio anuncio;
	
	private List<Municipio> municipios;
	private List<Ramo> ramos;
	private List<Servico> servicos;
	private List<Estado> estados; 
	private List<String> bairros;
	private List<Servico> topServicos;
	private List<Municipio> topMunicipios;
	private List<String> topBairros;
	private List<Estado> topEstados;

	public String searchMain() {
		
		try {
			this.municipio = municipioDao.findById(this.municipio.getId());
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {						
						anuncios = anuncioDao.searchAnunciosPaginadaByRamo(first, pageSize, ramo, municipio);
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}
					return anuncios;
				}

				@Override
				public int getRowCount() {
					return anuncioDao.countAnunciosByRamo(ramo, municipio).intValue();
				}

				@Override
				public int getPageSize() {
					return pageSize;
				}				
			};
			
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
			
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.topEstados = municipioDao.maxEstadosByAnuncio();
			this.ramo = ramoDao.findById(getRamo().getId());
			this.municipio = municipioDao.findById(getMunicipio().getId());
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}		
		return "/faces/site/xhtml/search.xhtml";
	}
	
	public String searchByServico() {
		
		try {
			
			
			setMunicipio(municipioDao.findById(getMunicipio().getId()));
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {
						anuncios = anuncioDao.searchAnunciosPaginadaByServico(first, pageSize, servico, estado);
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}
					return anuncios;
				}

				@Override
				public int getPageSize() {
					return pageSize;
				}

				@Override
				public int getRowCount() {
					return anuncioDao.countAnunciosByServico(servico, estado).intValue();
				}
				
			};			
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
		
			this.municipio = municipioDao.findById(this.municipio.getId());
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.topEstados = municipioDao.maxEstadosByAnuncio();
		} catch (Exception e) {
			log.error(e.getMessage());
		}	
		return "/faces/site/xhtml/search.xhtml";
	}
	
	public void searchByMunicipio() {
		try {
			setMunicipio(municipioDao.findById(getMunicipio().getId()));
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {
						anuncios = anuncioDao.searchAnunciosPaginadaByMunicipio(first, pageSize, municipio);
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}					
					return anuncios;
				}

				@Override
				public int getRowCount() {					
					return anuncioDao.countAnunciosByMunicpio(municipio).intValue();
				}

				@Override
				public int getPageSize() {
					return pageSize;
				}				
			};						
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
		
			this.municipio = municipioDao.findById(this.municipio.getId());
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.topEstados = municipioDao.maxEstadosByAnuncio();
		} catch (Exception e) {
			log.error(e.getMessage());
		}		
	}
	
	public void searchByBairro() {
		
		try {
			setMunicipio(municipioDao.findById(getMunicipio().getId()));
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public int getPageSize() {
					return pageSize;
				}

				@Override
				public int getRowCount() {
					return anuncioDao.countAnunciosByBairro(bairro, estado).intValue();
				}

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {
						anuncios = anuncioDao.searchAnunciosPaginadaByBairro(first, pageSize, bairro, getMunicipio().getEstado());
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}
					return anuncios;
				}				
			};
			
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
		
			this.municipio = municipioDao.findById(this.municipio.getId());
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.topEstados = municipioDao.maxEstadosByAnuncio();
		} catch (Exception e) {
			log.error(e.getMessage());
		}		
		
	}
	
	public void searchByEstado() {
		
		try {
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public int getPageSize() {
					return pageSize;
				}

				@Override
				public int getRowCount() {
					return anuncioDao.countAnunciosByEstado(estado).intValue();
				}

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {
						anuncios = anuncioDao.searchAnunciosPaginadaByEstado(first, pageSize, estado);
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}					
					return anuncios;
				}
				
			};			
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
		
			this.municipio = municipioDao.findById(this.municipio.getId());
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.topEstados = municipioDao.maxEstadosByAnuncio();
		} catch (Exception e) {
			log.error(e.getMessage());
		}		
		
	}
	
	public void searchOpenFields() {
		
		try {
			lazyModelAnuncio = new LazyDataModel<Anuncio>() {

				@Override
				public int getPageSize() {
					return pageSize;
				}

				@Override
				public int getRowCount() {
					return anuncioDao.countAnuncios(getSearchField()).intValue();
				}

				@Override
				public List<Anuncio> load(int first, int pageSize, String sortField, SortOrder order, Map<String, String> filters) {
					List<Anuncio> anuncios = null;
					try {
						anuncios = anuncioDao.searchAnunciosPaginada(first, pageSize, getSearchField());
					} catch (Exception e) {
						log.error(e.getMessage(),e);
					}
					return anuncios;
				}				
			};			
			this.avaliacao = new Avaliacao();	
			this.mensagem = new Mensagem();
			this.anuncio = new Anuncio();
			/* carrega topServicos para filtro */
		
			this.municipio = municipioDao.findById(this.municipio.getId());
			this.topServicos = servicoDao.maxServicosByAnuncio(this.municipio.getEstado());
			this.topMunicipios = municipioDao.maxMunicipiosByAnuncio(this.municipio.getEstado());
			this.topBairros = municipioDao.maxBairrosByAnuncio(this.municipio.getEstado());
			this.ramo = ramoDao.findById(getRamo().getId());
			this.municipio = municipioDao.findById(getMunicipio().getId());
		} catch (Exception e) {
			log.error(e.getMessage());
		}		
		
	}
	
	@PostConstruct
	public void loadFields() {
		try {			
			Estado estado = estadoDao.findPorSigla(UF_DEFAULT);
			// carrega listas para combos
			this.municipios = municipioDao.listMunicipiosPorUFComAnunciosOrdemNome(estado);
			this.ramos = ramoDao.listRamosOrdemNome();
			this.estados = estadoDao.listEstadosComAnunciosOrdemSigla();	
			this.servicos = servicoDao.listServicosOrdemNovos();
			// carrega estado default
			this.estado = estado;
			this.ramo = new Ramo();
			this.municipio = new Municipio();	
			this.servico = new Servico();
			
		} catch (Exception e) {
			log.error(e.getMessage());
			this.municipios = new ArrayList<Municipio>();
		}
	}
	
	public void reloadMunicipios() {
		try {
			this.municipios = municipioDao.listMunicipiosPorUFComAnunciosOrdemNome(estado);
		} catch (Exception e) {
			log.error(e.getMessage());
			this.municipios = new ArrayList<Municipio>();
		}		
		
	}
	
	public void handleRate() {
		
		try {
			List<Avaliacao> avaliacoes = this.anuncio.getAvaliacoes();
			if (avaliacoes != null) {
				avaliacoes.add(this.avaliacao);
			} else {
				avaliacoes = new ArrayList<Avaliacao>();
				avaliacoes.add(this.avaliacao);
			}
			this.anuncio.setAvaliacoes(avaliacoes);
			anuncioDao.merge(this.anuncio);
			if (this.avaliacao.getTipo().name().equals(TipoAvaliacao.A.name())) {
				this.anuncio.setReputacaoAtendimento( anuncioDao.calculaReputacao(anuncio,TipoAvaliacao.A));
			} else {
				this.anuncio.setReputacaoServico( anuncioDao.calculaReputacao(anuncio,TipoAvaliacao.S));
			}			
			anuncioDao.merge(this.anuncio);
			this.avaliacao = new Avaliacao();
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		} 
	}
	
	public void sendMessage() {
		
		try {
			List<Mensagem> mensagens = this.anuncio.getMensagens();			
			this.mensagem.setDataEnvio(Calendar.getInstance().getTime());
			if (mensagens != null) {
				mensagens.add(this.mensagem);
			} else {
				mensagens = new ArrayList<Mensagem>();
				mensagens.add(this.mensagem);
			}
			this.anuncio.setMensagens(mensagens);
			anuncioDao.merge(this.anuncio);
						
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}				
	}
	
	public void loadSelectedAnuncio(RateEvent event) {
		
		UIComponent ratingComponent = event.getComponent();
        Long idAnuncio = (Long) ratingComponent.getAttributes().get("idAnuncio");
        String tipoAvaliacao = (String) ratingComponent.getAttributes().get("tipo");        
        try {
			this.anuncio = anuncioDao.forceEagerLoad(idAnuncio);
			this.avaliacao.setClassificacao((Double)event.getRating());
			if (TipoAvaliacao.A.name().equals(tipoAvaliacao)) {
				this.avaliacao.setTipo(TipoAvaliacao.A);
			} else {
				this.avaliacao.setTipo( TipoAvaliacao.S );
			}			
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}        		
	}
	
	public void loadAnuncioById() {
		try {			
			String idAnuncio = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idAnuncio");
			if (idAnuncio != null)
				this.anuncio = anuncioDao.forceEagerLoad(Long.parseLong(idAnuncio));
						
		} catch (NumberFormatException e) {
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
	}
	
	public void auditarClick() {
		try {			
			String tipoAuditoria = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("tipo");
			TipoAuditoria tipo = TipoAuditoria.valueOf(tipoAuditoria);
			
			String idAnuncio = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("idAnuncio");
			
			if (idAnuncio != null)
				this.anuncio = anuncioDao.findById(Long.parseLong(idAnuncio));
			
			Auditoria auditoria = new Auditoria();
			auditoria.setAnuncio(this.anuncio);
			auditoria.setTipo(tipo);
			auditoria.setData(Calendar.getInstance().getTime());
			
			auditoriaDao.persist(auditoria);						
		} catch (NumberFormatException e) {
			log.error(e.getMessage(),e);
		} catch (Exception e) {
			log.error(e.getMessage(),e);
		}
	}

	public Estado getEstado() {
		return estado;
	}

	public void setEstado(Estado estado) {
		this.estado = estado;
	}

	public List<Municipio> getMunicipios() {
		return municipios;
	}

	public void setMunicipios(List<Municipio> municipios) {
		this.municipios = municipios;
	}

	public List<Estado> getEstados() {
		return estados;
	}

	public void setEstados(List<Estado> estados) {
		this.estados = estados;
	}

	public Anuncio getAnuncio() {
		return anuncio;
	}

	public void setAnuncio(Anuncio anuncio) {
		this.anuncio = anuncio;
	}

	public LazyDataModel<Anuncio> getLazyModelAnuncio() {
		return lazyModelAnuncio;
	}

	public void setLazyModelAnuncio(LazyDataModel<Anuncio> lazyModelAnuncio) {
		this.lazyModelAnuncio = lazyModelAnuncio;
	}

	public Integer getPageSize() {
		return pageSize;
	}

	public Municipio getMunicipio() {
		return municipio;
	}

	public void setMunicipio(Municipio municipio) {
		this.municipio = municipio;
	}

	public Ramo getRamo() {
		return ramo;
	}

	public void setRamo(Ramo ramo) {
		this.ramo = ramo;
	}

	public List<Ramo> getRamos() {
		return ramos;
	}

	public void setRamos(List<Ramo> ramos) {
		this.ramos = ramos;
	}

	public List<Servico> getTopServicos() {
		return topServicos;
	}

	public void setTopServicos(List<Servico> topServicos) {
		this.topServicos = topServicos;
	}

	public List<Estado> getTopEstados() {
		return topEstados;
	}

	public void setTopEstados(List<Estado> topEstados) {
		this.topEstados = topEstados;
	}

	public Avaliacao getAvaliacao() {
		return avaliacao;
	}

	public void setAvaliacao(Avaliacao avaliacao) {
		this.avaliacao = avaliacao;
	}

	public Servico getServico() {
		return servico;
	}

	public void setServico(Servico servico) {
		this.servico = servico;
	}

	public String getSearchField() {
		return searchField;
	}

	public void setSearchField(String searchField) {
		this.searchField = searchField;
	}

	public List<Municipio> getTopMunicipios() {
		return topMunicipios;
	}

	public void setTopMunicipios(List<Municipio> topMunicipios) {
		this.topMunicipios = topMunicipios;
	}

	public List<String> getTopBairros() {
		return topBairros;
	}

	public void setTopBairros(List<String> topBairros) {
		this.topBairros = topBairros;
	}

	public Mensagem getMensagem() {
		return mensagem;
	}

	public void setMensagem(Mensagem mensagem) {
		this.mensagem = mensagem;
	}

	public String getBairro() {
		return bairro;
	}

	public void setBairro(String bairro) {
		this.bairro = bairro;
	}

	public List<Servico> getServicos() {
		return servicos;
	}

	public void setServicos(List<Servico> servicos) {
		this.servicos = servicos;
	}

}
